// perl_documenteventsink.cpp - document event sink

#include "PlPN.h"

/*
 * PerlDocumentEventSink
 */

PerlDocumentEventSink::PerlDocumentEventSink(extensions::IDocumentPtr doc, SV* perl_doc) {
	m_doc = doc;
	SvREFCNT_inc(perl_doc);
	m_perl_doc = perl_doc;
}

PerlDocumentEventSink::~PerlDocumentEventSink() {
	if (m_perl_doc != NULL)
		SvREFCNT_dec(m_perl_doc);
}

void PerlDocumentEventSink::OnSchemeChange(const char* scheme) {
	if (m_perl_doc == NULL)
		return;

	SV* sv_scheme = newSVpv(scheme, 0);	// length of 0 means Perl will calculate

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		XPUSHs(sv_scheme);	// length of 0 means Perl will calculate
		PUTBACK;
	
		call_method("OnSchemeChange", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnSchemeChange: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	SvREFCNT_dec(sv_scheme);	// don't need this any more

	return;
}

void PerlDocumentEventSink::OnDocClosing() {
	if (m_perl_doc == NULL)
		return;

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		PUTBACK;
	
		call_method("OnDocClosing", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnDocClosing: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	
	// stop tracking the document in the global tracker
	g_document_tracker.Remove(m_doc);
	
	return;
}

void PerlDocumentEventSink::OnAfterLoad() {
	if (m_perl_doc == NULL)
		return;

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		PUTBACK;
	
		call_method("OnAfterLoad", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnAfterLoad: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	
	return;
}

void PerlDocumentEventSink::OnBeforeSave(const wchar_t* filename) {
	if (m_perl_doc == NULL)
		return;

	char* utf8_filename = wide_2_utf8(filename);
	SV* sv_filename(newSVpv(utf8_filename, 0));	// length of 0 means Perl will calculate
	
	// caller responsible for freeing memory after wide_2_utf8
	free((void*)utf8_filename);

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		XPUSHs(sv_filename);
		PUTBACK;
	
		call_method("OnBeforeSave", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnBeforeSave: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	SvREFCNT_dec(sv_filename);	// don't need this any more
	
	return;
}

void PerlDocumentEventSink::OnAfterSave() {
	if (m_perl_doc == NULL)
		return;

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		PUTBACK;
	
		call_method("OnAfterSave", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnAfterSave: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	
	return;
}

void PerlDocumentEventSink::OnModifiedChanged(bool modified) {
	if (m_perl_doc == NULL)
		return;

	SV* sv_modified = modified ? &PL_sv_yes : &PL_sv_no;

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		XPUSHs(sv_modified);
		PUTBACK;
	
		call_method("OnModifiedChanged", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnModifiedChanged: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	
	return;
}

void PerlDocumentEventSink::OnWriteProtectChanged(bool writeProtect) {
	if (m_perl_doc == NULL)
		return;

	SV* sv_writeProtect = writeProtect ? &PL_sv_yes : &PL_sv_no;

	// call the event for every perl sink we're tracking
	for (int i = 0; i < m_perl_sinks.size(); i++) {
		dSP;

		ENTER;
		SAVETMPS;

		PUSHMARK(SP);
		XPUSHs(m_perl_sinks[i]);
		XPUSHs(m_perl_doc);
		XPUSHs(sv_writeProtect);
		PUTBACK;
	
		call_method("OnWriteProtectChanged", G_VOID|G_EVAL);
		SPAGAIN;

		if(SvTRUE(ERRSV)) {
			STRLEN n_a;
			alert("Error calling Perl version of OnWriteProtectChanged: %s\n", SvPV(ERRSV,n_a));
		}
	
		PUTBACK;
		FREETMPS;
		LEAVE;
	}
	
	return;
}
